/**
 @file sys_at_mcu.c

 @author  Copyright (C) 2019 Centec Networks Inc.  All rights reserved.

 @date 2021-12-03

 @version v0.1

*/

/****************************************************************************
 *
 * Header Files
 *
 ****************************************************************************/
#include "sal.h"
#include "ctc_error.h"
#include "ctc_debug.h"
#include "ctc_interrupt.h"
#include "ctc_warmboot.h"
#include "drv_api.h"
#include "usw/include/drv_common.h"
#include "sys_usw_common.h"
#include "sys_usw_datapath.h"
#include "sys_usw_mac.h"
#include "sys_usw_eunit.h"
#include "sys_tmg_mcu_fw.inc"
#include "sys_usw_mcu.h"
#include "sys_tmg_mcu.h"
#include "sys_tmg_datapath.h"

/****************************************************************************
 *
 * Defines and Macros
 *
 *****************************************************************************/
extern sal_file_t g_tm_dump_fp;
extern uint8 g_dmps_dbg_sw;
extern sys_datapath_master_t* p_usw_datapath_master[];


/* DRV_IOW_FIELD extender, for index Not Zero */
#define DRV_IOW_FIELD_NZ(lchip, memid, fieldid, value, ptr, inst, index) \
     do\
     {\
         int retv = 0;\
         char   fld_str[64] = {0};\
         retv = drv_set_field(lchip, memid, fieldid, ptr, value);\
         if (retv < 0)\
         {\
             return(retv); \
         }\
         drv_usw_get_field_string_by_id(lchip, memid, fieldid, fld_str);\
         if ((NULL != g_tm_dump_fp) && (g_dmps_dbg_sw)) \
         {\
             sal_fprintf(g_tm_dump_fp, "//write chip 0 tbl-reg  %s.%d  %d  field %s %d\n", \
                 TABLE_NAME(lchip, memid), inst, index, fld_str, *value); \
             sal_fflush(g_tm_dump_fp);\
         }\
     }\
     while(0)


extern uint8
_sys_tmg_mac_is_power_up(uint8 lchip, uint8 txqm_id);



#define ____MCU_SYS_REG_IO____
int32
_sys_tmg_mcu_write_mcumem_drv(uint8 lchip, uint8 mcu_id, uint32 offset_addr, uint32 mask, uint32 value)
{
    uint32 cmd       = 0;
    uint32 entry_id  = offset_addr / SYS_TMG_MCUMEM_BYTES;
    uint32 index     = DRV_INS(mcu_id, entry_id);
    uint32 m_mem[SYS_TMG_MCUMEM_WORDS]  = {0x0};
    uint32 bit       = 0;
    uint32 raw_data  = 0;
    uint32 mask_op   = ~mask;

    SYS_CONDITION_RETURN(SYS_TMG_MCU_NUM <= mcu_id, CTC_E_INVALID_CONFIG);

    /* read total entry */
    cmd = DRV_IOR(McpuMem_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, index, cmd, m_mem));

    /* Modified value */
    if(0x0 != mask)
    {
        for(bit = 0; 0 == ((mask_op >> bit) & 0x1); bit++);
        
        value = value << bit;
        raw_data = m_mem[(offset_addr % SYS_TMG_MCUMEM_BYTES) / SYS_TMG_MCUMEM_WORDS];
        value |= (raw_data & mask);
    }
    
    m_mem[(offset_addr % SYS_TMG_MCUMEM_BYTES) / SYS_TMG_MCUMEM_WORDS] = value;

    cmd = DRV_IOW(McpuMem_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, index, cmd, m_mem));

    return CTC_E_NONE;
}

int32
_sys_tmg_mcu_read_mcumem_drv(uint8 lchip, uint8 mcu_id, uint32 offset_addr, uint32 mask, uint32 *value)
{
    uint32 cmd       = 0;
    uint32 entry_id  = offset_addr / SYS_TMG_MCUMEM_BYTES;
    uint32 index     = DRV_INS(mcu_id, entry_id);
    uint32 m_mem[SYS_TMG_MCUMEM_WORDS]  = {0x0};
    uint32 bit       = 0;
    uint32 raw_data  = 0;
    uint32 mask_op   = ~mask;

    SYS_CONDITION_RETURN(SYS_TMG_MCU_NUM <= mcu_id, CTC_E_INVALID_CONFIG);

    /* read total entry */
    cmd = DRV_IOR(McpuMem_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, index, cmd, m_mem));

    raw_data = m_mem[(offset_addr % SYS_TMG_MCUMEM_BYTES) / SYS_TMG_MCUMEM_WORDS];
    raw_data &= mask_op;
    for(bit = 0; 0 == ((mask_op >> bit) & 0x1); bit++);
    *value = raw_data >> bit;

    return CTC_E_NONE;
}

int32 
sys_tmg_mcu_hw_intf_init(uint8 lchip, uint8 mcu_id, uint8 init)
{   
    uint32 index     = 0;
    uint32 cmd       = 0;
    uint32 value     = 0;
    uint32 tbl_id    = 0;
    uint32 field_id  = 0;

    McuIntfInit_m  McuIntfInit;

    /* #1, index, tbl_id, field_id */
    index = DRV_INS(mcu_id, 0);
    tbl_id    = McuIntfInit_t;
    field_id  = McuIntfInit_init_f;

    /* #2, read HW table */
    cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, index, cmd, &McuIntfInit));

    /* #3. modify field value */
    value = init ? 1 : 0;
    DRV_IOW_FIELD_NZ(lchip, tbl_id, field_id, &value, &McuIntfInit, mcu_id, 0);

    /* #4, write HW table */
    cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, index, cmd, &McuIntfInit));

    return CTC_E_NONE;
}

int32 
sys_tmg_mcu_hw_hsctl_reset(uint8 lchip, uint8 mcu_id, uint8 reset)
{   
    uint32 index     = 0;
    uint32 cmd       = 0;
    uint32 value     = 0;
    uint32 tbl_id    = 0;
    uint32 field_id  = 0;

    CtcHsCtlReset_m  CtcHsCtlReset;

    /* #1, index, tbl_id, field_id */
    index = DRV_INS(mcu_id, 0);
    tbl_id    = CtcHsCtlReset_t;
    field_id  = CtcHsCtlReset_resetCoreMcu_f;

    /* #2, read HW table */
    cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, index, cmd, &CtcHsCtlReset));

    /* #3. modify field value */
    value = reset ? 1 : 0;
    DRV_IOW_FIELD_NZ(lchip, tbl_id, field_id, &value, &CtcHsCtlReset, mcu_id, 0);

    /* #4, write HW table */
    cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, index, cmd, &CtcHsCtlReset));

    return CTC_E_NONE;
}

int32 
sys_tmg_mcu_hw_hsctl_intf_reset(uint8 lchip, uint8 mcu_id, uint8 reset)
{   
    uint32 index     = 0;
    uint32 cmd       = 0;
    uint32 value     = 0;
    uint32 tbl_id    = 0;
    uint32 field_id  = 0;

    CtcHsCtlReset_m  CtcHsCtlReset;

    /* #1, index, tbl_id, field_id */
    index = DRV_INS(mcu_id, 0);
    tbl_id    = CtcHsCtlReset_t;
    field_id  = CtcHsCtlReset_resetCoreMcuIntf_f;

    /* #2, read HW table */
    cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, index, cmd, &CtcHsCtlReset));

    /* #3. modify field value */
    value = reset ? 1 : 0;
    DRV_IOW_FIELD_NZ(lchip, tbl_id, field_id, &value, &CtcHsCtlReset, mcu_id, 0);

    /* #4, write HW table */
    cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, index, cmd, &CtcHsCtlReset));

    return CTC_E_NONE;
}

int32 
sys_tmg_mcu_hw_miscctl_reset(uint8 lchip, uint8 reset)
{   
    uint32 index     = 0;
    uint32 cmd       = 0;
    uint32 value     = 0;
    uint32 tbl_id    = 0;
    uint32 field_id  = 0;

    CtcMiscCtlReset_m  CtcMiscCtlReset;

    /* #1, index, tbl_id, field_id */
    index = DRV_INS(0, 0);
    tbl_id    = CtcMiscCtlReset_t;
    field_id  = CtcMiscCtlReset_resetMcu_f;

    /* #2, read HW table */
    cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, index, cmd, &CtcMiscCtlReset));

    /* #3. modify field value */
    value = reset ? 1 : 0;
    DRV_IOW_FIELD_NZ(lchip, tbl_id, field_id, &value, &CtcMiscCtlReset, 0, 0);

    /* #4, write HW table */
    cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, index, cmd, &CtcMiscCtlReset));

    return CTC_E_NONE;
}

int32 
sys_tmg_mcu_hw_miscctl_intf_reset(uint8 lchip, uint8 reset)
{   
    uint32 index     = 0;
    uint32 cmd       = 0;
    uint32 value     = 0;
    uint32 tbl_id    = 0;
    uint32 field_id  = 0;

    CtcMiscCtlReset_m  CtcMiscCtlReset;

    /* #1, index, tbl_id, field_id */
    index = DRV_INS(0, 0);
    tbl_id    = CtcMiscCtlReset_t;
    field_id  = CtcMiscCtlReset_resetCoreMcuIntf_f;

    /* #2, read HW table */
    cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, index, cmd, &CtcMiscCtlReset));

    /* #3. modify field value */
    value = reset ? 1 : 0;
    DRV_IOW_FIELD_NZ(lchip, tbl_id, field_id, &value, &CtcMiscCtlReset, 0, 0);

    /* #4, write HW table */
    cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, index, cmd, &CtcMiscCtlReset));

    return CTC_E_NONE;
}

/*
 * grand_id : 0 - 7
 * bit      : 0 - 31
 */

int32
sys_tmg_mcu_hw_lock(uint8 lchip, uint32 mcu_id, uint8 grand_id, uint8 bit)
{
    uint32 value      = 0;
    uint32 cmd        = 0;
    uint32 entry_id   = 0;
    uint32 inst_id    = SYS_TMG_MCU_ID_PER_CORE(mcu_id);
    uint32 ext_tbl_id = McpuGrant0ExtCtl_t + grand_id;
    uint32 index      = DRV_INS(inst_id, entry_id);


    if(p_drv_master[lchip]->wb_status == DRV_WB_STATUS_RELOADING)
    {
        return CTC_E_NONE;
    }

    /* param check */
    if ((grand_id > TMG_MCU_MAX_GRAND_ID) || (bit > TMG_MCU_MAX_GRAND_BIT_ID))
    {
        return CTC_E_INVALID_PARAM;
    }

    /* Get Lock */
    while(1)
    {
        cmd  = DRV_IOR(ext_tbl_id, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, index, cmd, &value));

        CTC_BIT_SET(value, bit);

        cmd  = DRV_IOW(ext_tbl_id, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, index, cmd, &value));

        cmd  = DRV_IOR(ext_tbl_id, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, index, cmd, &value));

        if (CTC_IS_BIT_SET(value, bit))
        {
            break;
        }
    }

    return CTC_E_NONE;
}

/*
 * grand_id : 0 - 7
 * bit      : 0 - 31
 */

int32
sys_tmg_mcu_hw_unlock(uint8 lchip, uint32 mcu_id, uint8 grand_id, uint32 bit)
{
    uint32 value      = 0;
    uint32 cmd        = 0;
    uint32 entry_id   = 0;
    uint32 inst_id    = SYS_TMG_MCU_ID_PER_CORE(mcu_id);
    uint32 ext_tbl_id = McpuGrant0ExtCtl_t + grand_id;
    uint32 index      = DRV_INS(inst_id, entry_id);

